﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using DiscoveryLogic.Common.Utilities;
using DiscoveryLogic.DataViz.NetworkDiagram.Layouts;
using DiscoveryLogic.WindowsUserControl.UIUpdateWrapper;

namespace DiscoveryLogic.DataViz.NetworkDiagram
{
    /// <summary>
    /// 
    /// </summary>
    public partial class GraphRenderTest : Form
    {
        private IGraphLayout _Render = null;

        /// <summary>
        /// 
        /// </summary>
        public GraphRenderTest()
        {
            InitializeComponent();
        }

        private void GraphRenderTest_Load(object sender, EventArgs e)
        {
            this.cbo_Algorithms.Items.Clear();
            for(int i=0;i<=1;i++)
            {
                GraphLayoutAlgorithm algorithm = (GraphLayoutAlgorithm) i;
                this.cbo_Algorithms.Items.Add(algorithm.ToString());
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
			List<Vertice> Vs = new List<Vertice>();
			List<Edge> Es = new List<Edge>();
        	this.ParseNetworkData(this.txt_NetworkDataFilePath.Text,
        	                      this.cbo_NodePath.Text, this.cbo_NodeID.Text, this.cbo_NodeLabel.Text,
        	                      this.cbo_EdgePath.Text, this.cbo_EdgeID.Text, this.cbo_EdgeLength.Text,
        	                      this.cbo_From.Text, this.cbo_To.Text,
        	                      ref Vs, ref Es);
            this._Render=new ForceDirectedLayout();
            this._Render.ShowVerticeLabels = this.ck_ShowLabel.Checked;
            this._Render.ShowEdgeDistances = this.ck_ShowDistance.Checked;
            this._Render.DistancePercentileCutoff = int.Parse(this.txt_DistancePercentileCutoff.Text);
            GraphLayoutAlgorithm algorithm = (GraphLayoutAlgorithm) this.cbo_Algorithms.SelectedIndex;
            this._Render.LayoutAlgorithm = algorithm;
            this._Render.GraphUpdated += new OnGraphUpdated(_FDForceDirectedGraph_GraphUpdated);

            ((ForceDirectedLayout)this._Render).SpringStiffness = (double)this.num_Spring.Value;
            ((ForceDirectedLayout)this._Render).ElectronicRepulsionFactor = (double)this.num_Electronic.Value;

            Graph g = new Graph();
            g.InitializeGraphObjects(Vs, Es);
            this._Render.Init(this.pictureBox1.Size, g);
            this._Render.StartRender(true);
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (this._Render != null)
                this._Render.StopRender();
        }

        private void btn_Browse_Click(object sender, EventArgs e)
        {
            OpenFileDialog dlg=new OpenFileDialog();
            dlg.Filter = "Network data(*.network;*.net;*.viz;*.xml)|*.network;*.net;*.viz;*.xml|All files(*.*)|*.*";
            if(dlg.ShowDialog()==DialogResult.OK)
            {
                this.txt_NetworkDataFilePath.Text = dlg.FileName;
                
				this.PopulateXPaths(dlg.FileName);
            }
        }

        void _FDForceDirectedGraph_GraphUpdated(Image img)
        {
            img.Save(@"C:\fd.png", ImageFormat.Png);
            new PictureBoxUpdator(this.pictureBox1, PictureBoxSizeMode.StretchImage, img);
        }

        private void ParseNetworkData(string filePath, string nodePath, string nodeIDAttr, string nodeLabelAttr,
			string edgePath, string edgeIDAttr, string edgeLengthAttr, string fromNodeAttr, string toNodeAttr,
			ref List<Vertice> vertices, ref List<Edge> edges)
        {
            edges=new List<Edge>();
			Dictionary<string,Guid> vLabels=new Dictionary<string, Guid>();
            XmlDocument xDoc = new XmlDocument();
            xDoc.Load(filePath);
			Dictionary<Guid, Vertice> vColl = new Dictionary<Guid, Vertice>();
			if (!string.IsNullOrEmpty(nodePath))
			{
				XmlNodeList verticeNodes = xDoc.SelectNodes(nodePath);
				if (verticeNodes != null && verticeNodes.Count > 0)
				{
					foreach (XmlNode vNode in verticeNodes)
					{
						Guid id = new Guid(XmlDataUtil.GetAttributeValue(vNode, nodeIDAttr, Guid.NewGuid().ToString()));
						string label = XmlDataUtil.GetAttributeValue(vNode, nodeLabelAttr, "");
						Vertice v = new Vertice(id, label, new PointF());
						
						vColl.Add(id, v);
						vLabels.Add(label, id);
					}
				}
			}
        	XmlNodeList edgeNodes = xDoc.SelectNodes(edgePath);
            if(edgeNodes !=null && edgeNodes.Count>0)
            {
                foreach(XmlNode eNode in edgeNodes)
                {
                    Guid id=new Guid(XmlDataUtil.GetAttributeValue(eNode, edgeIDAttr,Guid.NewGuid().ToString()));
                    string label = XmlDataUtil.GetAttributeValue(eNode, "Label", "");
                	string fromNodeLabel = XmlDataUtil.GetAttributeValue(eNode, fromNodeAttr, Guid.Empty.ToString());
                	Guid fromVID = Guid.NewGuid();
					if (vLabels.ContainsKey(fromNodeLabel))
						fromVID = vLabels[fromNodeLabel];
					else
					{
						vLabels.Add(fromNodeLabel,fromVID);
						Vertice v = new Vertice(fromVID,fromNodeLabel,new PointF());
						vColl.Add(fromVID,v);
					}
                	string toNodeLabel = XmlDataUtil.GetAttributeValue(eNode, toNodeAttr, Guid.Empty.ToString());
                	Guid toVID = Guid.NewGuid();
					if (vLabels.ContainsKey(toNodeLabel))
						toVID = vLabels[toNodeLabel];
					else
					{
						vLabels.Add(toNodeLabel,toVID);
						Vertice v = new Vertice(toVID, toNodeLabel, new PointF());
						vColl.Add(toVID, v);
					}
                    float len = float.Parse(XmlDataUtil.GetAttributeValue(eNode, edgeLengthAttr, "0"));
                    Edge e = new Edge(id, label, len, fromVID, toVID);
                    edges.Add(e);
                }
            }

			vertices = new List<Vertice>();
			if (vColl.Count > 0)
				vertices.AddRange(vColl.Values);
		}

		#region xml path
		private void PopulateXPaths(string xmlFilePath)
		{
			XmlTextReader xReader = new XmlTextReader(File.OpenRead(xmlFilePath));
			this.cbo_NodePath.Items.Clear();
			this.cbo_EdgePath.Items.Clear();
			List<string> allPaths = new List<string>();
			int lastDepth = -1;
			string lastNodeName = string.Empty;
			Stack<string> elementNames = new Stack<string>();
			while (xReader.Read())
			{
				if (xReader.NodeType == XmlNodeType.Element)
				{
					int currentDepth = xReader.Depth;
					if (currentDepth > lastDepth)
					{
						lastDepth = currentDepth;
						lastNodeName = xReader.Name;
						elementNames.Push(lastNodeName);
						string xPath = this.GetXPath(elementNames);
						if (!allPaths.Contains(xPath))
							allPaths.Add(xPath);
					}
					else if (currentDepth == lastDepth)
					{
						if (xReader.Name == lastNodeName)
							continue;
						else
						{
							lastNodeName = xReader.Name;
							if (elementNames.Count > 0)
								elementNames.Pop();
							elementNames.Push(lastNodeName);
							string xPath = this.GetXPath(elementNames);
							if (!allPaths.Contains(xPath))
								allPaths.Add(xPath);
						}
					}
					else
					{
						lastDepth = xReader.Depth;
						lastNodeName = xReader.Name;
						while (elementNames.Count > xReader.Depth)
							elementNames.Pop();
						elementNames.Push(lastNodeName);
						string xPath = this.GetXPath(elementNames);
						if (!allPaths.Contains(xPath))
							allPaths.Add(xPath);
					}
				}
			}
			xReader.Close();
			foreach (string xPath in allPaths)
			{
				this.cbo_NodePath.Items.Add(xPath);
				this.cbo_EdgePath.Items.Add(xPath);
			}
		}

		private string GetXPath(Stack<string> elementNames)
		{
			string[] elementNamesCopy = elementNames.ToArray();
			string path = string.Empty;
			for (int i = elementNamesCopy.Length - 1; i >= 0; i--)
			{
				if (path.Length > 0)
					path += "/";
				path += elementNamesCopy[i];
			}
			return path;
		}

		private void cbo_NodePath_SelectedIndexChanged(object sender, EventArgs e)
		{
			if (this.cbo_NodePath.SelectedIndex < 0)
				return;

			this.cbo_NodeID.Items.Clear();
			this.cbo_NodeLabel.Items.Clear();
			XmlDocument xDoc = new XmlDocument();
			xDoc.Load(this.txt_NetworkDataFilePath.Text);
			XmlNodeList xNodes = xDoc.SelectNodes(this.cbo_NodePath.SelectedItem.ToString());
			if (xNodes != null && xNodes.Count > 0)
			{
				XmlNode xNode = xNodes[0];
				foreach (XmlAttribute attr in xNode.Attributes)
				{
					this.cbo_NodeID.Items.Add(attr.Name);
					this.cbo_NodeLabel.Items.Add(attr.Name);
				}
			}
		}

		private void cbo_EdgePath_SelectedIndexChanged(object sender, EventArgs e)
		{
			if(this.cbo_EdgePath.SelectedIndex<0)
				return;

			this.cbo_EdgeID.Items.Clear();
			this.cbo_EdgeLength.Items.Clear();
			this.cbo_From.Items.Clear();
			this.cbo_To.Items.Clear();
			XmlDocument xDoc = new XmlDocument();
			xDoc.Load(this.txt_NetworkDataFilePath.Text);
			XmlNodeList xNodes = xDoc.SelectNodes(this.cbo_EdgePath.SelectedItem.ToString());
			if (xNodes != null && xNodes.Count > 0)
			{
				XmlNode xNode = xNodes[0];
				foreach (XmlAttribute attr in xNode.Attributes)
				{
					this.cbo_EdgeID.Items.Add(attr.Name);
					this.cbo_EdgeLength.Items.Add(attr.Name);
					this.cbo_From.Items.Add(attr.Name);
					this.cbo_To.Items.Add(attr.Name);
				}
			}
		}
		#endregion

        private void trackBar1_Scroll(object sender, EventArgs e)
        {
            this.txt_DistancePercentileCutoff.Text = this.trackBar1.Value.ToString();
        }
	}
}
